from fastapi import Depends, HTTPException, status
from typing import Optional, List, Dict, Any
from jose import JWTError, jwt
from datetime import datetime, timedelta
from passlib.context import CryptContext

from server.db.repositories.user_repository import UserRepository
from server.db.session import get_db
from server.core.config.settings import settings
from server.schemas.user import UserCreate, UserUpdate, UserRead, Token, TokenPayload
from server.db.models.user import User, Role, Permission
from sqlalchemy.ext.asyncio import AsyncSession

class UserService:
    def __init__(self,
                 user_repository: UserRepository = Depends(),
                 pwd_context: CryptContext = Depends(lambda: CryptContext(schemes=["bcrypt"], deprecated="auto"))):
        self.user_repository = user_repository
        self.pwd_context = pwd_context

    async def create_user(self, user_in: UserCreate, db: AsyncSession = Depends(get_db)) -> UserRead:
        """创建新用户"""
        # 检查用户名和邮箱是否已存在
        if await self.user_repository.user_exists(username=user_in.username, db=db):
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="用户名已存在"
            )

        if user_in.email and await self.user_repository.user_exists(email=user_in.email, db=db):
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="邮箱已存在"
            )

        # 创建用户
        user = await self.user_repository.create_user(user_in, db=db)
        return UserRead.from_orm(user)

    async def get_user(self, user_id: int, db: AsyncSession = Depends(get_db)) -> UserRead:
        """通过ID获取用户"""
        user = await self.user_repository.get_user_by_id(user_id, db=db)
        if not user:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="用户不存在"
            )
        return UserRead.from_orm(user)

    async def get_user_by_username(self, username: str, db: AsyncSession = Depends(get_db)) -> UserRead:
        """通过用户名获取用户"""
        user = await self.user_repository.get_user_by_username(username, db=db)
        if not user:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="用户不存在"
            )
        return UserRead.from_orm(user)

    async def update_user(self, user_id: int, user_in: UserUpdate, db: AsyncSession = Depends(get_db)) -> UserRead:
        """更新用户信息"""
        # 检查用户是否存在
        user = await self.user_repository.get_user_by_id(user_id, db=db)
        if not user:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="用户不存在"
            )

        # 如果更新用户名或邮箱，检查是否已被使用
        if user_in.username and user_in.username != user.username:
            if await self.user_repository.user_exists(username=user_in.username, db=db):
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="用户名已存在"
                )

        if user_in.email and user_in.email != user.email:
            if await self.user_repository.user_exists(email=user_in.email, db=db):
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="邮箱已存在"
                )

        # 更新用户
        user = await self.user_repository.update_user(user_id, user_in, db=db)
        return UserRead.from_orm(user)

    async def delete_user(self, user_id: int, db: AsyncSession = Depends(get_db)) -> bool:
        """删除用户"""
        # 防止删除自己
        # TODO: 获取当前用户ID并进行检查
        return await self.user_repository.delete_user(user_id, db=db)

    async def authenticate(self, username: str, password: str, db: AsyncSession = Depends(get_db)) -> Optional[User]:
        """用户认证"""
        return await self.user_repository.authenticate(username, password, db=db)

    def create_access_token(self, subject: int, additional_claims: Optional[Dict[str, Any]] = None) -> str:
        """创建访问令牌"""
        return self._create_token(
            subject=subject,
            expires_delta=timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES),
            additional_claims=additional_claims,
            token_type="access"
        )

    def create_refresh_token(self, subject: int) -> str:
        """创建刷新令牌"""
        return self._create_token(
            subject=subject,
            expires_delta=timedelta(days=settings.REFRESH_TOKEN_EXPIRE_DAYS),
            token_type="refresh"
        )

    def _create_token(self, subject: int, expires_delta: timedelta, token_type: str, additional_claims: Optional[Dict[str, Any]] = None) -> str:
        """创建JWT令牌"""
        claims = {
            "sub": str(subject),
            "type": token_type,
            "exp": datetime.utcnow() + expires_delta,
            "iat": datetime.utcnow()
        }

        if additional_claims:
            claims.update(additional_claims)

        encoded_jwt = jwt.encode(
            claims,
            settings.SECRET_KEY,
            algorithm=settings.ALGORITHM
        )
        return encoded_jwt

    def verify_token(self, token: str) -> TokenPayload:
        """验证令牌并返回负载"""
        try:
            payload = jwt.decode(
                token,
                settings.SECRET_KEY,
                algorithms=[settings.ALGORITHM]
            )
            user_id: str = payload.get("sub")
            if user_id is None:
                raise HTTPException(
                    status_code=status.HTTP_401_UNAUTHORIZED,
                    detail="无法验证凭据"
                )
            token_type: str = payload.get("type")
            if token_type != "access":
                raise HTTPException(
                    status_code=status.HTTP_401_UNAUTHORIZED,
                    detail="无效的令牌类型"
                )
            return TokenPayload(user_id=int(user_id))
        except JWTError:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="无法验证凭据"
            )

    async def get_current_user(self, token: str, db: AsyncSession = Depends(get_db)) -> UserRead:
        """获取当前登录用户"""
        payload = self.verify_token(token)
        user = await self.user_repository.get_user_by_id(payload.user_id, db=db)
        if not user:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="用户不存在"
            )
        return UserRead.from_orm(user)

    async def check_permission(self, user_id: int, permission_code: str, db: AsyncSession = Depends(get_db)) -> bool:
        """检查用户是否拥有指定权限"""
        user = await self.user_repository.get_user_by_id(user_id, db=db)
        if not user:
            return False
        return user.has_permission(permission_code)

    async def get_users(self, skip: int = 0, limit: int = 100, db: AsyncSession = Depends(get_db)) -> List[UserRead]:
        """获取用户列表"""
        users = await self.user_repository.get_users(skip, limit, db=db)
        return [UserRead.from_orm(user) for user in users]